package com.yqg.education.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.crypto.SecureUtil;
import com.alibaba.excel.EasyExcel;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.yqg.education.common.Constant;
import com.yqg.education.controller.dto.ImportQuestionDto;
import com.yqg.education.controller.dto.ImportUserDto;
import com.yqg.education.controller.dto.UserDTO;
import com.yqg.education.controller.dto.UserPasswordDTO;
import com.yqg.education.entity.Menu;
import com.yqg.education.entity.TrainClass;
import com.yqg.education.entity.User;
import com.yqg.education.entity.UserRole;
import com.yqg.education.exception.ServiceException;
import com.yqg.education.listener.QuestionListener;
import com.yqg.education.listener.UserListener;
import com.yqg.education.mapper.*;
import com.yqg.education.service.IMenuService;
import com.yqg.education.service.ITrainClassService;
import com.yqg.education.service.IUserService;
import com.yqg.education.utils.Constants;
import com.yqg.education.utils.JwtTokenUtil;
import com.yqg.education.utils.RedisUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.net.URLEncoder;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * UserServiceImpl 服务实现类
 *
 * @author zxf
 * @since 2025-03-01
 */
@Service
@Slf4j
public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements IUserService {

    private final RedisUtil redisUtil;

    private final JwtTokenUtil jwtTokenUtil;

    @Resource
    private UserMapper userMapper;

    @Resource
    private RoleMapper roleMapper;

    @Resource
    private UserRoleMapper userRoleMapper;

    @Resource
    private MenuMapper menuMapper;

    @Resource
    private IMenuService menuService;

    @Resource
    private ClassStudentMapper classStudentMapper;

    @Resource
    private ClassCourseMapper classCourseMapper;

    @Resource
    private ITrainClassService trainClassService;

    @Resource
    UserListener userListener;

    public UserServiceImpl(RedisUtil redisUtil, JwtTokenUtil jwtTokenUtil) {
        this.redisUtil = redisUtil;
        this.jwtTokenUtil = jwtTokenUtil;
    }

    @Override
    public UserDTO login(UserDTO userDTO) {
        // 用户密码 md5加密
        userDTO.setPassword(SecureUtil.md5(userDTO.getPassword()));
        User user = userMapper.getLoginUser(userDTO.getTelephone(), userDTO.getPassword());
        if (user != null) {
            //获取当前角色id
            Integer roleId = userDTO.getRole();
            LambdaQueryWrapper<UserRole> userRoleWrapper = new LambdaQueryWrapper<>();
            userRoleWrapper.eq(UserRole::getUserId, user.getId());
            userRoleWrapper.eq(UserRole::getRoleId, roleId);
            UserRole userRole = userRoleMapper.selectOne(userRoleWrapper);
            if (userRole != null) {
                List<Menu> menus = menuMapper.selectMenus(roleId);
                List<Menu> treeMenu = menuService.getTreeMenu(menus);
                userDTO.setMenus(treeMenu);
                BeanUtil.copyProperties(user, userDTO, true);
                // 设置token
                String token = jwtTokenUtil.generateToken(user);
                HashMap<String, Integer> map = new HashMap<>();
                map.put("userId", userDTO.getId());
                map.put("roleId", roleId);
                redisUtil.hmset(token, map, Constants.EXPIRATION_TIME);
                userDTO.setToken(token);
                return userDTO;
            } else {
                throw new ServiceException(Constant.CODE_401, "用户无此权限");
            }
        } else {
            throw new ServiceException(Constant.CODE_600, "用户名或密码错误");
        }
    }

    @Override
    public User register(UserDTO userDTO) {
        // 用户密码 md5加密
        userDTO.setPassword(SecureUtil.md5(userDTO.getPassword()));
        User user = userMapper.getLoginUser(userDTO.getUsername(), userDTO.getPassword());
        if (user == null) {
            user = new User();
            BeanUtil.copyProperties(userDTO, user, true);
            save(user);  // 把 copy完之后的用户对象存储到数据库
        } else {
            throw new ServiceException(Constant.CODE_600, "用户已存在");
        }
        return user;
    }

    @Override
    public void updatePassword(UserPasswordDTO userPasswordDTO) {
        int update = userMapper.updatePassword(userPasswordDTO);
        if (update < 1) {
            throw new ServiceException(Constant.CODE_600, "密码错误");
        }
    }

    /**
     * 重置密码(123456)
     */
    @Override
    public int resetPwd(int id, String password, Date date) {
        return userMapper.resetPwd(id, password, date);
    }

    /**
     * 从数据库查询用户信息
     *
     * @param request
     * @param flag 若flag为1，表示需要返回班级名称信息
     * @return User
     */
    @Override
    public UserDTO getUserInfo(HttpServletRequest request,String flag) {
        String token = request.getHeader("token");
        Map<Object, Object> map = redisUtil.hmget(token);
        Integer userId = (Integer) map.get("userId");
        Integer roleId = (Integer) map.get("roleId");
        User user = userMapper.selectById(userId);
        LambdaQueryWrapper<UserRole> userRoleWrapper = new LambdaQueryWrapper<>();
        userRoleWrapper.eq(UserRole::getUserId, userId);
        userRoleWrapper.eq(UserRole::getRoleId, roleId);
        UserRole userRole = userRoleMapper.selectOne(userRoleWrapper);
        UserDTO userDTO = new UserDTO();
        userDTO.setRole(roleId);
        userDTO.setToken(token);

//        学员端新增添加班级名称
        if ("1".equals(flag)) {
            Integer classIdByUserId = classStudentMapper.getClassIdByUserId(userId);
            if (classIdByUserId != null) {
                TrainClass classById = trainClassService.getById(classIdByUserId);
                userDTO.setClassName(classById.getTrainClassNum());
            }
        }

        if (userRole != null) {
            List<Menu> menus = menuMapper.selectMenus(roleId);
            List<Menu> treeMenu = menuService.getTreeMenu(menus);
            userDTO.setMenus(treeMenu);
        }
        BeanUtil.copyProperties(user, userDTO, true);
        return userDTO;
    }

    public List<Long> getCourseIdByUserId(Integer userId) {
        Integer classId = classStudentMapper.getClassIdByUserId(userId);
        return classCourseMapper.getCourseIdByClassId((long) classId);
    }

    @Override
    public void importData(MultipartFile file) {
        try {
            EasyExcel.read(file.getInputStream(), ImportUserDto.class, userListener)
                    .sheet(0).headRowNumber(1).doRead();
        } catch (Exception e) {
            log.info("导入异常，请稍后重试！", e);
        }
    }

    @Override
    public void exportStu(HttpServletResponse response, String name, String telephone, Integer roleId, Integer classId) {
        try {
            //设置下载
            response.setContentType("application/vnd.ms-excel");
            response.setCharacterEncoding("utf-8");
            // 这里URLEncoder.encode可以防止中文乱码 当然和easyexcel没有关系
            String fileName = null;
            fileName = URLEncoder.encode("学生信息表", "UTF-8");
            response.setHeader("Content-disposition", "attachment;filename=" + fileName + ".xlsx");

            //查询用户所有数据
            List<User> exportData = userMapper.exportStuData(name,telephone,roleId,classId);
            //EasyExcel 写操作
            EasyExcel.write(response.getOutputStream(), User.class)
                    .sheet("学生信息表")
                    .doWrite(exportData);
        } catch (Exception e) {
            log.info("exception ", e);
        }
    }
}
